PHP 有預定義一些 interface 及 class,妥善運用這些類別與介面,有助於讓標準函式或敘述式使用它們,也易於讓其它開發者理解。
實現了 Traversable
的 class 表示它可以被 foreach
。
Iterator
或 IteratorAggregate
的 interface 中被繼承instanceof
做搭配if( is_array( $items ) || $items instanceof Traversable ) {
// 表示 $items 可以用 foreach
foreach ($items as $item) { }
}
Iterator
又稱「迭代器」,這是 Traversable
的具現化之一。
Iterator
需要實現五個 methods
current(): mixed
:取得目前的項目key(): scalar
:取得目前項目的索引next(): void
:取得下一個項目rewind(): void
:回到第一個項目valid(): bool
:確認目前位置是否有效,通常在 next()
或 rewind()
之後使用class DemoIterator implements Iterator
{
private $position = 0;
private $data = ['one', 'two', 'three'];
public function currnet()
{
return $this->data[$position];
}
public function key()
{
return $this->position;
}
public function next()
{
$this->position++;
}
public function rewind()
{
$this->position = 0;
}
public function valid()
{
return isset($this->data[$this->position]);
}
}
IteratorAggregate
又稱「聚合迭代器」,是另一個 Traversable
的具現化。
IteratorAggregate
需要實現一個 method:
getIterator(): Traversable
:直接回傳具有 Traversable
的 Class,它有助於整合多個 Iterator
或其它實現了 Traversable
的 Class。class DemoIteratorAggregate implements IteratorAggregate
{
private $data1;
private $data2;
public function __construct()
{
$this->data1 = [1, 2, 3];
$this->data2 = new ArrayIterator([4, 5, 6]);
}
public function getIterator()
{
return new ArrayIterator([$this->data1, $this->data2]);
}
}
Throwable
表示該 Class 可被 throw
,這實現於 Error
及 Exception
(PHP 7 之後,內部 Error 會被當作一個可被 catch 存在)
通常 Throwable
不會自行實現,因為通常都是建立 Exception
,但與 Traversable
不同 Throwable
是可以被直接拿來使用的。
try {
} catch(Exception $e) {
// 表示丟出 Exception,這通常是出現一些邏輯層的問題
} catch (Error $e) {
// 表示丟出 Error,這通常是語法上具有問題(例如 type error)
}
// 我們可以將上敘述式簡化為
try {
} catch (Throwable $e) {
}
ArrayAccess
表示該類別所建立出來的變數可以像 array 一樣直接使用 offset 存取。
ArrayAccess
需要實現四個 methods:
offsetExists(mixed $offset): bool
:確認 offset 是否存在offsetGet(mixed $offset): mixed
:取得該 offset 所在之值offsetSet(mixed $offset, mixed $value): void
:為指定的 offset 設定 valueoffsetUnset(mixed $offset): void
:移除指定的 offsetclass DemoArrayAccess implements ArrayAccess
{
private $data = [1, 2, 3];
public function offsetExists($offset)
{
return isset($this->data[$offset]);
}
public function offsetGet($offset)
{
return $this->data[$offset];
}
public function offsetSet($offset, $value)
{
$offset === null
? $this->data[] = $value;
: $this->data[$offset] = $value;
}
public function offsetUnset($offset)
{
unset($this->data[$offset]);
}
}
Serializable
表示此 Class 可以被「序列化」,序列化表示將一個 Class 的資訊轉為 string,有需要時可以利用該 string 還原回原本的 Class:例如將一個 class 做 json_encode()
就是一種序列化,它只要再被 json_decode()
就可以還原回來。
值得注意的是,如果 Class 有實現 __sleep()
及 __wakeup()
再實現 Serializable
,__sleep()
及 __wakeup()
會失效。
Serializable
需要實現兩個 methods:
serialize(): string
:表示序列化所需的操作unserialize(string $serialized): void
:表示反序列化時的操作class DemoSerializable implements Serializable
{
private $data = 'My Data';
public function serialize()
{
return $this->data;
}
public function unserialize(string $serialized)
{
$this->data = $serialized;
}
}
$obj = new DemoSerializable();
$serialized = serialize($obj);
$unserialized = unserialize($obj);
Closure
主要用於表示匿名函式。
$a = function () { echo 'hello world'; }
$a instanceof Closure; // true
Generator
主要用於 yield
的回傳值,這部份可參考我昨天的文章:Day 06: yield 的使用。
值得注意的是,Generator
無法被 new
出來。
function generator(): Generator
{
yield 1;
yield 2;
yield 3;
}
foreach (generator() as $item) {
}
WeakReference
是一個來自於 WeakRef
的 extension,在 PHP 7.4 之後被加入標準之中。
Weak Reference 又名「弱引用」,這在部份的物件導向程式設計中被認為是優化 GC 行為的一項 Feature。
PHP 的 GC 與 Java 類似,當兩個條件達成時,使用的記憶體就會被回收
class A
{
}
$a = new A; // $a 與 Class A 是引用關係,在 unset($a) 或生命週期結束之前它不會被 GC。
WeakReference
的引入目的在於做到類似於「Object 的快取」:當 Object 存活時,WeakReference 就可以使用它,當 Object 被回收時,WeakReference 也不會阻止 GC 去回收它。
class A
{
}
$a = new A;
$b = $a;
$weakA = WeakReference::create($a);
$weakA->get(); // object (A)#1 (0) {}
unset($a)
$weakA->get(); // null
通常預定義的 Interface 及 Class 比較常用於 Array 系列(Iterator、ArrayAccess),事實上只要瞭解如何使用就能寫出易於理解的程式碼